// cl /O2 /MD /LD add.c
#include "jni.h" // also need jni_md.h

__declspec(dllexport) int __cdecl add(int a, int b)
{
    return a + b;
}

__declspec(dllexport) int __cdecl add_back(int a, int b, int (*cb)(int,int))
{
    return cb(a, b);
}

__declspec(dllexport) int __cdecl addNaked(int __, int a, int b)
{
    return a + b;
}

__declspec(dllexport) void __cdecl dummy()
{
}

// public static native int nativeAdd(int a, int b);
JNIEXPORT jint JNICALL Java_TestFFI_nativeAdd(JNIEnv* jenv, jclass jcls, jint a, jint b)
{
    return a + b;
}

// public static native int nativeAddBack(int a, int b, IntBinaryOperator cb);
JNIEXPORT jint JNICALL Java_TestFFI_nativeAddBack(JNIEnv* jenv, jclass jcls, jint a, jint b, jobject cb)
{
    jclass c = (*jenv)->GetObjectClass(jenv, cb);
    if (!c)
        return -1;
    jmethodID mid = (*jenv)->GetMethodID(jenv, c, "applyAsInt", "(II)I");
    if (!mid)
        return -2;
    return (*jenv)->CallIntMethod(jenv, cb, mid, a, b);
}


JNIEXPORT jint JNICALL Java_TestJNI_nativeAdd(JNIEnv* jenv, jclass jcls, jint a, jint b)
{
    return a + b;
}
JNIEXPORT jint JNICALL JavaCritical_TestJNI_nativeAdd(jint a, jint b) // only for JDK17-
{
    return a + b;
}

JNIEXPORT jint JNICALL Java_TestJNI_nativeAddBack(JNIEnv* jenv, jclass jcls, jint a, jint b, jobject cb)
{
    jclass c = (*jenv)->GetObjectClass(jenv, cb);
    if (!c)
        return -1;
    jmethodID mid = (*jenv)->GetMethodID(jenv, c, "applyAsInt", "(II)I");
    if (!mid)
        return -2;
    return (*jenv)->CallIntMethod(jenv, cb, mid, a, b);
}
